<template>
    <el-card shadow="never">
        <el-form :model="criteria" :inline="true" label-width="70px" style="text-align: left;">
            <el-form-item label="应用平台">
                <ApplicationSelect />
            </el-form-item>
            <el-form-item label="关键字" prop="keyword">
                <el-input v-model="criteria!.keyword" placeholder="角色名称" clearable></el-input>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="handleQuery">查询</el-button>
            </el-form-item>
        </el-form>
    </el-card>
    <el-card shadow="never">
        <div class="el-card-grid-container">
            <div class="button-container">
                <el-button type="primary" @click="openDialog('add')">添加</el-button>
            </div>
            <el-table v-loading="loading" :data="list">
                <el-table-column label="角色名称" prop="name" align="center"></el-table-column>
                <el-table-column label="所属租户" prop="tenant" align="center"></el-table-column>
                <el-table-column label="角色代码" prop="code" align="center"></el-table-column>
                <el-table-column label="描述" prop="intro" align="center"></el-table-column>
                <el-table-column label="操作" align="center">
                    <template #default="scope">
                        <el-button type="primary" :link="true" @click="openDialog('edit', scope.row.id)">修改</el-button>
                        <el-button type="primary" :link="true" @click="removeRole(scope.row.id)">删除</el-button>
                        <el-button type="primary" :link="true" @click="openDrawer(scope.row.id)">权限</el-button>
                    </template>
                </el-table-column>
            </el-table>
            <div class="el-pagination-container">
                <el-pagination
                v-show="total > 0"
                :page-size="paginationRequest.pageSize"
                :page-sizes="[10, 20, 50, 100]"
                :current-page="paginationRequest.pageIndex"
                :total="total"
                layout="total, sizes, prev, pager, next, jumper"
                @size-change="(size: number) => paginationRequest.pageSize = size"
                @current-change="(page: number) => paginationRequest.pageIndex = page" />
            </div>
        </div>    
    </el-card>

    <el-dialog v-model="dialog.visible" :title="dialog.title" :modal="true" width="40%">
        <el-form :model="formData" :rules="rules" ref="dialogFormRef" label-width="130px">
            <el-form-item label="角色名称" prop="name">
                <el-input v-model="formData.name" autocomplete="off" />
            </el-form-item>
            <el-form-item label="角色代码" prop="code">
                <el-input v-model="formData.code" autocomplete="off" />
            </el-form-item>
            <el-form-item label="角色描述" prop="intro">
                <el-input v-model="formData.intro" type="textarea" :autosize="{ minRows: 3, maxRows: 4 }" />
            </el-form-item>
        </el-form>
        <template #footer>
            <el-button @click="dialog.visible = false">取消</el-button>
            <el-button type="primary" @click="saveDialog">保存</el-button>
        </template>
    </el-dialog>

    <el-drawer v-model="drawerVisible" title="角色授权">
        <el-tree ref="authorizeTreeRef" :data="assignableTree" :props="treeProps" :check-strictly="true" v-on="eventHandler"
            node-key="id" empty-text="没有可授权的资源" show-checkbox default-expand-all>
        </el-tree>
    </el-drawer>
</template>

<script lang="ts" setup>
import type {RoleAuthorization, RoleGridView, RoleQueryCriteria} from "@/api/role/types"
import * as role from "@/api/role"
import type { TreeNode } from "@/api/resource/types"
import * as resource from "@/api/resource"
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus"

const paginationRequest = reactive<PaginationRequest<RoleQueryCriteria>>({
    pageIndex: 1,
    pageSize: 10,
    criteria: {
        keyword: ''
    },
    order: {
        property: "id",
        direction: 'DESC'
    }
})

const {criteria} = toRefs(paginationRequest)

const loading = ref(false)
const list = ref<RoleGridView[]>([])
const total = ref(0)

const handleQuery = async () => {
    paginationRequest.pageIndex = 1

    await query(paginationRequest)
}

const query = async (paginationCriteria: PaginationRequest<RoleQueryCriteria>) => {
    loading.value = true
    try {
        const pagination = await role.query(paginationCriteria)
        list.value = pagination.data || []
        total.value = pagination.total
    } catch (error) {
        ElMessage.error('查询失败')
        console.error(error)
    } finally {
        loading.value = false
    }
}

const removeRole = async (roleId: string) => {
    ElMessageBox.confirm('确定要删除该角色吗？', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(async () => {
        const result = await role.remove(roleId)
        if(result.success) {
            ElMessage.success(result.message)
            handleQuery()
        } else {
            ElMessage.error(result.message)
        }
    })
}


const dialog = reactive({
    action: '',
    visible: false,
    title: '',
    roleId: ''
})

const emptyForm = {
    name: '',
    code: '',
    intro: ''
}
const formData = ref(emptyForm)
const dialogFormRef = ref<FormInstance>()

const rules = reactive<FormRules>({
    name: [
        { required: true, message: '请输入角色名称', trigger: 'blur' },
        { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
    ],
    code: [
        { required: true, message: '请输入角色代码', trigger: 'blur' },
        { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
    ],
    intro: [
        { required: true, message: '请输入角色描述', trigger: 'blur' },
        { min: 5, max: 100, message: '长度在 5 到 100 个字符', trigger: 'blur' }
    ]
})

const openDialog = async (action: string, roleId?: string) => {
    dialog.action = action
    dialog.roleId = roleId || ''

    if(action === 'add') {
        dialog.title = '添加角色'
        formData.value = emptyForm
    } else if(action === 'edit') {
        dialog.title = '修改角色'
        if(!roleId) {
            ElMessage.error('角色ID不能为空')
            return
        }

        formData.value = await role.getForm(roleId)
    }
    
    dialog.visible = true
}

const saveDialog = () => {
    const handleResult = (result: ApiResult<string>) => {
        if(result.success) {
            ElMessage.success(result.message)
            handleQuery()
        } else {
            ElMessage.error(result.message)
        }

        dialog.visible = false
    }

    dialogFormRef.value?.validate((valid, fields) => {
        if (valid) {
            if(dialog.action === 'add') {
                role.add(formData.value).then((result) => {
                    handleResult(result)
                })
            } else if(dialog.action === 'edit') {
                role.edit(dialog.roleId, formData.value).then((result) => {
                    handleResult(result)
                })
            }
        }
    })
}


const authorizeTreeRef = ref()

const drawerVisible = ref(false)

const assignableTree = ref<TreeNode[]>([])

const authorizeRoleId = ref('')

onMounted(async () => {
    handleQuery()

    assignableTree.value = await resource.tree()
})

const treeProps = {
    children: 'children',
    label: 'name'
}

const eventHandler = reactive<{
    [key: string]: (...args: any[]) => void
}>({})

const openDrawer = async (roleId: string) => {
    authorizeRoleId.value = roleId
    delete eventHandler['check-change']

    const resources = await role.getAuthorizedResources(roleId)

    drawerVisible.value = true
    await nextTick()
    // 第一次不起作用
    authorizeTreeRef.value?.setCheckedKeys(resources)

    await nextTick()
    eventHandler['check-change'] = treeCheckChange
}

const treeCheckChange = async (node: TreeNode, checked: boolean) => {
    const data: RoleAuthorization = {
        roleId: authorizeRoleId.value,
        resourceId: node.id
    }

    if(checked) {
        await role.authorize(data)
        ElMessage.success(`${node.name} 权限添加成功`)
    } else {
        await role.unauthorize(data)
        ElMessage.info(`${node.name} 权限移除成功`)
    }
}
</script>

<style lang="scss" scoped>
.el-card-grid-container {
    .button-container {
        float: left;
        margin-bottom: 15px;
    }

    .el-pagination-container {
        display: flex;
        margin-top: 15px;

        .el-pagination {
            margin-left: auto;
        }
    }

}
</style>